/*
 * Copyright (c) 2022-2023 cetcclout Co., Ltd All rights reserved.
 * Sensor Adapter is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package com.cetccloud.cimp.common.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.compress.utils.Sets;

import cn.hutool.core.collection.CollUtil;

/**
 * 
 * @author
 * @apiNote Stream操作相关工具类
 */
public class StreamUtils {

   private StreamUtils() {
   }

   /**
    * 提取对象中的某一个属性
    *
    * @param srcList 对象list
    * @param mapper  对象::get属性名
    * @param <T>     对象类型
    * @param <R>     属性类型
    * @return 属性list
    */
   public static <T, R> List<R> toList(List<T> srcList, Function<? super T, ? extends R> mapper) {
       if (CollectionUtils.isEmpty(srcList)) {
           return Lists.newArrayList();
       }
       return srcList.stream().map(mapper).collect(Collectors.toList());
   }

   /**
    * 提取对象中的某一个属性，去重
    *
    * @param srcList 对象list
    * @param mapper  对象::get属性名
    * @param <T>     对象类型
    * @param <R>     属性类型
    * @return 属性set
    */
   public static <T, R> Set<R> toSet(List<T> srcList, Function<? super T, ? extends R> mapper) {
       if (CollectionUtils.isEmpty(srcList)) {
           return Sets.newHashSet();
       }
       return srcList.stream().filter(e -> mapper.apply(e) != null).map(mapper).collect(Collectors.toSet());
   }

   /**
    * ListSum求和
    *
    * @param srcList
    * @param toIntFunction
    * @param <T>
    * @return
    */
   public static <T> int sum(List<T> srcList, ToIntFunction<? super T> toIntFunction) {
       if (CollectionUtils.isEmpty(srcList)) {
           return 0;
       }
       return srcList.stream().mapToInt(toIntFunction).sum();
   }

   /**
    * 构建 属性:属性  map
    *
    * @param srcList 对象list
    * @param mapper1 对象::get属性名
    * @param mapper2 对象::get属性名
    * @param <T>     对象类型
    * @param <K>     属性类型
    * @param <U>     属性类型
    * @return 属性:属性 map
    */
   public static <T, K, U> Map<K, U> toMap(List<T> srcList,
                                           Function<? super T, ? extends K> mapper1,
                                           Function<? super T, ? extends U> mapper2) {
       if (CollectionUtils.isEmpty(srcList)) {
           return new HashMap<>();
       }
       return srcList.stream().collect(Collectors.toMap(mapper1, mapper2));
   }

   /**
    * 构建 属性:属性  map
    *
    * @param srcList 对象list
    * @param mapper1 对象::get属性名
    * @param mapper2 对象::get属性名
    * @param <T>     对象类型
    * @param <K>     属性类型
    * @param <U>     属性类型
    * @return 属性:属性 map
    */
   public static <T, K, U> Map<K, U> toMap(List<T> srcList,
                                           Function<? super T, ? extends K> mapper1,
                                           Function<? super T, ? extends U> mapper2,
                                           BinaryOperator<U> mergeFunction) {
       if (CollectionUtils.isEmpty(srcList)) {
           return new HashMap<>();
       }
       return srcList.stream().collect(Collectors.toMap(mapper1, mapper2, mergeFunction));
   }

   /**
    * 按特定规则筛选集合元素，返回List，过滤输入集合的null对象
    *
    * @param <T>       对象类型
    * @param source    对象集合
    * @param predicate 筛选条件
    * @return
    */
   public static <T> List<T> filter(Collection<T> source, Predicate<T> predicate) {
       if (CollectionUtils.isEmpty(source)) {
           return new ArrayList<>(0);
       }
       return source.stream().filter(Objects::nonNull).filter(predicate).collect(Collectors.toList());
   }

   /**
    * 按匹配条件返回某一个对象，过滤输入集合的null对象
    *
    * @param <T>       对象类型
    * @param source    对象集合
    * @param predicate 匹配条件
    * @return
    */
   public static <T> T findAny(Collection<T> source, Predicate<T> predicate) {
       if (CollectionUtils.isEmpty(source)) {
           return null;
       }
       return source.stream().filter(Objects::nonNull).filter(predicate).findAny().orElse(null);
   }

   /**
    * 判断集合是否有元素符合匹配条件
    *
    * @param <T>       对象类型
    * @param source    对象集合
    * @param predicate 匹配条件
    * @return
    */
   public static <T> boolean anyMatch(Collection<T> source, Predicate<T> predicate) {
       if (CollectionUtils.isEmpty(source)) {
           return false;
       }
       return source.stream().anyMatch(predicate);
   }

   /**
    * list分组
    *
    * @param srcList   对象list
    * @param keyMapper 分组属性
    * @param <T>
    * @param <R>
    * @return
    */
   public static <T, R> Map<R, List<T>> groupBy(List<T> srcList, Function<? super T, ? extends R> keyMapper) {
       if (CollectionUtils.isEmpty(srcList)) {
           return new HashMap<>();
       }
       return srcList.stream().collect(Collectors.groupingBy(keyMapper));
   }

   /**
    * 获取最大值
    *
    * @param srcList   对象list
    * @param keyMapper 对象获取方法
    * @param <T>
    * @return
    */
   public static <T, V> V max(List<T> srcList, Function<? super T, ? extends Comparable<V>> keyMapper) {
       if (CollUtil.isEmpty(srcList)) {
           return null;
       }
       V result = null;
       for (T t : srcList) {
           if (keyMapper.apply(t) != null && (result == null || keyMapper.apply(t).compareTo(result) > 0)) {
               result = (V) keyMapper.apply(t);
           }
       }
       return result;
   }

   /**
    * 获取最小值
    *
    * @param srcList   对象list
    * @param keyMapper 对象获取方法
    * @param <T>
    * @return
    */
   public static <T, V> V min(List<T> srcList, Function<? super T, ? extends Comparable<V>> keyMapper) {
       if (CollUtil.isEmpty(srcList)) {
           return null;
       }
       V result = null;
       for (T t : srcList) {
           if (keyMapper.apply(t) != null && (result == null || keyMapper.apply(t).compareTo(result) < 0)) {
               result = (V) keyMapper.apply(t);
           }
       }
       return result;
   }

   /**
    * 所有的都要匹配
    *
    * @param collection 集合
    * @param predicate  过滤条件
    * @return boolean
    */
   public static <T> boolean allMatch(Collection<T> collection, Predicate<T> predicate) {
       if (CollUtil.isEmpty(collection)) {
           return false;
       }
       return collection.stream().allMatch(predicate);
   }

   /**
    * 根据某个属性去重
    */
   public static <T> List<T> distinct(Collection<T> source, Function<? super T, ?> keyExtractor) {
       if (CollectionUtils.isEmpty(source)) {
           return new ArrayList<>(0);
       }
       return source.stream().filter(distinctByKey(keyExtractor))
               .collect(Collectors.toList());
   }
   private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
       Set<Object> seen = ConcurrentHashMap.newKeySet();
       return t -> seen.add(keyExtractor.apply(t));
   }


}
